#!/usr/bin/env python
# -*- coding:utf-8 -*-

# file:monitor.py.py
# author:吴凯博
# datetime:2022/5/1 16:24
# software: PyCharm
"""
this is function description
"""
import datetime
from threading import Lock

import psutil

from config.settings import Settings


class Monitor(object):
    __class_lock = Lock()
    __instance = None

    def __new__(cls, *args, **kwargs):
        """
        以单例模式创建监控器
        :param args:
        :param kwargs:
        """
        cls.__class_lock.acquire()

        if not cls.__instance:
            cls.__instance = super().__new__(cls)

        cls.__class_lock.release()

        return cls.__instance

    def __init__(self):
        if hasattr(self, '_cpu_data'):
            return
        self._record_lock = Lock()
        self._init_lock = Lock()
        # self._timer_lock = Lock()
        self._time_data = {}
        self._cpu_data = {}
        self._memory_data = {}
        self._net_data = {}
        # self._timer = None
        # self._timer_stat = 0
        self.init_data()

    def init_data(self) -> None:
        """
        初始化监控数据
        :return:
        """
        self._init_lock.acquire()

        self._cpu_data = {
            'cpu_percent': [None] * Settings.DATA_POINTS
        }
        memory_status = psutil.virtual_memory()
        self._memory_data = {
            'total': round(memory_status.total / pow(1024, 3, ), 2),
            'memory_percent': [None] * Settings.DATA_POINTS,
            'memory_free': [None] * Settings.DATA_POINTS,
            'memory_used': [None] * Settings.DATA_POINTS
        }
        self._time_data = {
            'time': [None] * Settings.DATA_POINTS
        }
        net_io = psutil.net_io_counters(pernic=True)
        net_addr = psutil.net_if_addrs()
        net_stat = psutil.net_if_stats()
        self._net_data = {
            net_name: {
                'MAC': net_addr[net_name][0].address,
                'IPv4': net_addr[net_name][1].address,
                'IPv6': net_addr[net_name][2].address,
                'last_recv': net_io[net_name].bytes_recv,
                'last_sent': net_io[net_name].bytes_sent,
                'bytes_recv': [None] * Settings.DATA_POINTS,
                'bytes_sent': [None] * Settings.DATA_POINTS
            } for net_name in net_stat.keys() if net_stat[net_name].isup and len(net_addr[net_name]) >= 3
        }

        self._init_lock.release()

    def record_data(self) -> dict:
        """
        采集并记录当前时刻的CPU占用百分比、内存占用百分比、可用内存、已用内存和当前时刻
        :return: 采集的数据样本
        """
        self._record_lock.acquire()

        if len(self._cpu_data.keys()) == 0:
            self.init_data()

        cpu_percent = psutil.cpu_percent()
        memory_status = psutil.virtual_memory()
        current_time = datetime.datetime.now()
        net_io = psutil.net_io_counters(pernic=True)

        self._cpu_data['cpu_percent'] = self._cpu_data['cpu_percent'][1:] + [cpu_percent]
        self._memory_data['memory_percent'] = self._memory_data['memory_percent'][1:] + [memory_status.percent]
        self._memory_data['memory_free'] = self._memory_data['memory_free'][1:] + [round(memory_status.free / pow(1024, 3), 2)]
        self._memory_data['memory_used'] = self._memory_data['memory_used'][1:] + [round(memory_status.used / pow(1024, 3), 2)]
        self._time_data['time'] = self._time_data['time'][1:] + [current_time.strftime("%y-%m-%d %H:%M:%S.%f")]
        for net_name in self._net_data.keys():
            if self._net_data[net_name]['last_recv'] != 0:
                new_recv = net_io[net_name].bytes_recv - self._net_data[net_name]['last_recv']
            else:
                new_recv = 0
            if self._net_data[net_name]['last_sent'] != 0:
                new_sent = net_io[net_name].bytes_sent - self._net_data[net_name]['last_sent']
            else:
                new_sent = 0
            self._net_data[net_name]['bytes_recv'] = self._net_data[net_name]['bytes_recv'][1:] + [round(new_recv / 1024, 2)]
            self._net_data[net_name]['bytes_sent'] = self._net_data[net_name]['bytes_sent'][1:] + [round(new_sent / 1024, 2)]
            self._net_data[net_name]['last_recv'] = net_io[net_name].bytes_recv
            self._net_data[net_name]['last_sent'] = net_io[net_name].bytes_sent

        self._record_lock.release()

        return self.get_data()

    def get_data(self) -> dict:
        """
        获取采集的数据样本
        :return: {
            'cpu_data': {
                'cpu_percent': [float] CPU占用百分比
            },
            'memory_data': {
                'total': float 总内存（GB）,
                'memory_percent': [float] 内存占用百分比,
                'memory_free': [float] 空闲内存（GB）,
                'memory_used': [float] 已用内存（GB）
            },
            'time_data': {
                'time': [str] 当前数据采集时刻，年-月-日 时:分:秒
            },
            'net_data': {
                '网络名称': {
                    'MAC': str 该网络的MAC地址,
                    'IPv4': str 该网络的IPv4地址,
                    'IPv6': str 该网络的IPv6地址,
                    'bytes_recv': [int] 接收数据量（KB）,
                    'bytes_sent': [int] 发送数据量（KB）
                },
                ...
            }
        }
        """
        # self._timer_lock.acquire()
        self._record_lock.acquire()

        return_data = {
            'cpu_data': self._cpu_data,
            'memory_data': self._memory_data,
            'time_data': self._time_data,
            'net_data': {
                net_name: {
                    'MAC': self._net_data[net_name]['MAC'],
                    'IPv4': self._net_data[net_name]['IPv4'],
                    'IPv6': self._net_data[net_name]['IPv6'],
                    'bytes_recv': self._net_data[net_name]['bytes_recv'],
                    'bytes_sent': self._net_data[net_name]['bytes_sent']
                } for net_name in self._net_data.keys()
            }
        }

        self._record_lock.release()
        # self._timer_lock.release()
        return return_data

    # def start(self) -> None:
    #     """
    #     开始采集数据样点
    #     :return:
    #     """
    #     self._timer_lock.acquire()
    #     if not self._timer_stat:
    #         self._timer_stat = 1
    #         self._init_data()
    #         self._timer = Thread(target=self.record_data)
    #         self._timer.start()
    #     self._timer_lock.release()

    # def cancel(self) -> None:
    #     """
    #     结束采集数据样点
    #     :return:
    #     """
    #     self._timer_lock.acquire()
    #     if self._timer_stat:
    #         self._timer_stat = 0
    #         self._timer.join(timeout=0)
    #     self._timer_lock.release()


if __name__ == '__main__':
    monitor = Monitor()
    # monitor.start()
    # time.sleep(3)
    # a = monitor.get_data()
    # print(a['cpu_data']['cpu_percent'])
    # monitor.cancel()
    # b = monitor.get_data()
    # print(b['cpu_data']['cpu_percent'])
    monitor.record_data()
    print(monitor._cpu_data)
    monitor2 = Monitor()
    print(monitor2._cpu_data)
